package com.zhiwen.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zhiwen.domain.entity.Category;
import com.zhiwen.domain.entity.Question;
import com.zhiwen.domain.entity.SearchHistory;
import com.zhiwen.domain.entity.SearchKeyword;
import com.zhiwen.domain.entity.User;
import com.zhiwen.mapper.QuestionMapper;
import com.zhiwen.mapper.SearchHistoryMapper;
import com.zhiwen.mapper.SearchKeywordMapper;
import com.zhiwen.mapper.UserMapper;
import com.zhiwen.service.CategoryService;
import com.zhiwen.service.SearchService;
import com.zhiwen.service.UserService;
import com.zhiwen.domain.vo.QuestionVO;
import com.zhiwen.domain.vo.UserVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 搜索服务实现类 - 使用注解简化版本
 *
 * @author zhiwen
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SearchServiceImpl implements SearchService {

    // 依赖注入 - 使用final字段和@RequiredArgsConstructor自动生成构造器
    private final QuestionMapper questionMapper;
    private final UserMapper userMapper;
    private final SearchHistoryMapper searchHistoryMapper;
    private final SearchKeywordMapper searchKeywordMapper;
    private final UserService userService;
    private final CategoryService categoryService;
    private final RedisTemplate<String, Object> redisTemplate;

    // 配置属性注入
    @Value("${app.search.hot-keywords-key:search:hot_keywords}")
    private String hotKeywordsKey;

    @Value("${app.search.cache-expiration:30}")
    private long cacheExpiration;

    @Value("${app.search.max-keywords:5}")
    private int maxKeywordsPerSearch;

    @Override
    @Cacheable(value = "searchQuestions",
            key = "#keyword + '_' + #page.current + '_' + #page.size + '_' + #sort",
            unless = "#result.total == 0",
            condition = "#keyword != null && !#keyword.trim().isEmpty()")
    public Page<QuestionVO> searchQuestions(String keyword, Page<Question> page, Integer sort) {
        log.debug("搜索问题: 关键词={}, 排序={}", keyword, sort);

        // 使用StringUtils工具类判断空字符串
        if (!StringUtils.hasText(keyword)) {
            return getLatestQuestions(page);
        }

        String processedKeyword = keyword.trim();
        String[] keywords = processedKeyword.split("\\s+");

        // 限制关键词数量防止性能问题
        if (keywords.length > maxKeywordsPerSearch) {
            keywords = Arrays.copyOf(keywords, maxKeywordsPerSearch);
        }

        QueryWrapper<Question> queryWrapper = buildSearchQueryWrapper(keywords, processedKeyword);
        applySortOrder(queryWrapper, sort);

        Page<Question> questionPage = questionMapper.selectPage(page, queryWrapper);
        Page<QuestionVO> voPage = convertToQuestionVOPage(questionPage);

        // 异步记录搜索
        asyncRecordSearch(processedKeyword);

        return voPage;
    }

    @Override
    @Cacheable(value = "searchUsers",
            key = "#keyword + '_' + #page.current + '_' + #page.size",
            unless = "#result.total == 0")
    public Page<UserVO> searchUsers(String keyword, Page<User> page) {
        log.debug("搜索用户: 关键词={}", keyword);

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("username", keyword)
                .or().like("nickname", keyword)
                .or().like("bio", keyword);

        queryWrapper.eq("status", 1);
        queryWrapper.eq("deleted", 0);

        Page<User> userPage = userMapper.selectPage(page, queryWrapper);
        return convertToUserVOPage(userPage);
    }

    @Override
    @Cacheable(value = "hotKeywords", key = "#limit")
    public List<String> getHotKeywords(Integer limit) {
        log.debug("获取热门关键词: {}", limit);

        // 先从Redis获取
        Set<ZSetOperations.TypedTuple<Object>> typedTuples
                = redisTemplate.opsForZSet().reverseRangeWithScores(hotKeywordsKey, 0, limit - 1);

        if (typedTuples != null && !typedTuples.isEmpty()) {
            return typedTuples.stream()
                    .map(tuple -> (String) tuple.getValue())
                    .collect(Collectors.toList());
        }

        // 从数据库获取并同步到Redis
        return getAndCacheHotKeywordsFromDB(limit);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveSearchHistory(Long userId, String keyword, Integer type) {
        log.debug("保存搜索历史: 用户={}, 关键词={}", userId, keyword);

        try {
            updateHotKeyword(keyword);

            SearchHistory history = new SearchHistory();
            history.setUserId(userId);
            history.setKeyword(keyword);
            history.setType(type);

            return searchHistoryMapper.insert(history) > 0;
        } catch (Exception e) {
            log.error("保存搜索历史失败", e);
            return false;
        }
    }

    @Override
    @Cacheable(value = "userSearchHistory", key = "#userId + '_' + #limit",cacheManager = "shortTermCacheManager")
    public List<String> getUserSearchHistory(Long userId, Integer limit) {
        QueryWrapper<SearchHistory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.orderByDesc("create_time");
        queryWrapper.last("LIMIT " + limit);

        return searchHistoryMapper.selectList(queryWrapper).stream()
                .map(SearchHistory::getKeyword)
                .distinct()
                .collect(Collectors.toList());
    }

    @Override
    @CacheEvict(value = "userSearchHistory", key = "#userId + '*'",cacheManager = "shortTermCacheManager")
    public boolean clearUserSearchHistory(Long userId) {
        try {
            QueryWrapper<SearchHistory> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId);
            return searchHistoryMapper.delete(queryWrapper) >= 0;
        } catch (Exception e) {
            log.error("清空搜索历史失败", e);
            return false;
        }
    }

    @Override
    @Cacheable(value = "searchAll", key = "#keyword + '_' + #current + '_' + #size")
    public Map<String, Object> searchAll(String keyword, Integer current, Integer size) {
        Map<String, Object> result = new HashMap<>();

        // 并行搜索提高性能
        CompletableFuture<Page<QuestionVO>> questionsFuture = CompletableFuture
                .supplyAsync(() -> searchQuestions(keyword, new Page<>(current, size), 1));

        CompletableFuture<Page<UserVO>> usersFuture = CompletableFuture
                .supplyAsync(() -> searchUsers(keyword, new Page<>(current, Math.min(size, 5))));

        try {
            result.put("questions", questionsFuture.get());
            result.put("users", usersFuture.get());
            result.put("keyword", keyword);
        } catch (Exception e) {
            log.error("综合搜索失败", e);
            result.put("questions", new Page<>());
            result.put("users", new Page<>());
        }

        return result;
    }

    @Override
    @Cacheable(value = "searchTags", key = "#keyword + '_' + #limit")
    public List<String> searchRelatedTags(String keyword, Integer limit) {
        QueryWrapper<Question> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("tags");
        queryWrapper.like("tags", keyword);
        queryWrapper.eq("status", 1);
        queryWrapper.eq("deleted", 0);
        queryWrapper.isNotNull("tags");
        queryWrapper.ne("tags", "");
        queryWrapper.last("LIMIT " + (limit * 3)); // 获取更多数据以便过滤

        List<Question> questions = questionMapper.selectList(queryWrapper);

        Set<String> relatedTags = new HashSet<>();
        String lowerKeyword = keyword.toLowerCase();

        for (Question question : questions) {
            if (StringUtils.hasText(question.getTags())) {
                String[] tags = question.getTags().split(",");
                Arrays.stream(tags)
                        .map(String::trim)
                        .filter(tag -> !tag.isEmpty() && tag.toLowerCase().contains(lowerKeyword))
                        .forEach(relatedTags::add);
            }

            if (relatedTags.size() >= limit) {
                break;
            }
        }

        return new ArrayList<>(relatedTags).subList(0, Math.min(relatedTags.size(), limit));
    }

    @Override
    @Cacheable(value = "searchSuggestions",
            key = "#keyword + '_' + #limit",
            cacheManager = "shortTermCacheManager")
    public List<String> getSearchSuggestions(String keyword, Integer limit) {
        if (!StringUtils.hasText(keyword)) {
            return getHotKeywords(limit);
        }

        List<String> suggestions = new ArrayList<>();
        String lowerKeyword = keyword.toLowerCase();

        // 1. 从热门关键词中匹配
        List<String> hotKeywords = getHotKeywords(limit * 2);
        suggestions.addAll(hotKeywords.stream()
                .filter(k -> k.toLowerCase().contains(lowerKeyword))
                .limit(limit / 2)
                .collect(Collectors.toList()));

        // 2. 从问题标题中获取建议
        if (suggestions.size() < limit) {
            QueryWrapper<Question> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("title");
            queryWrapper.like("title", keyword);
            queryWrapper.eq("status", 1);
            queryWrapper.eq("deleted", 0);
            queryWrapper.orderByDesc("view_count");
            queryWrapper.last("LIMIT " + (limit - suggestions.size()));

            List<Question> questions = questionMapper.selectList(queryWrapper);
            suggestions.addAll(questions.stream()
                    .map(Question::getTitle)
                    .collect(Collectors.toList()));
        }

        return suggestions.stream().distinct().limit(limit).collect(Collectors.toList());
    }

    @Override
    public Page<QuestionVO> advancedSearch(String keyword, String tags, Long userId, String startDate,
            String endDate, Integer minViews, Integer minAnswers,
            Page<Question> page, Integer sort) {

        QueryWrapper<Question> queryWrapper = new QueryWrapper<>();

        // 基础条件
        queryWrapper.eq("status", 1);
        queryWrapper.eq("deleted", 0);

        // 关键词搜索
        if (StringUtils.hasText(keyword)) {
            String[] keywords = keyword.trim().split("\\s+");
            if (keywords.length > 1) {
                queryWrapper.and(wrapper -> {
                    for (String k : keywords) {
                        if (StringUtils.hasText(k)) {
                            wrapper.or(w -> w.like("title", k)
                                    .or().like("content", k)
                                    .or().like("tags", k));
                        }
                    }
                });
            } else {
                queryWrapper.and(wrapper -> wrapper.like("title", keyword)
                        .or().like("content", keyword)
                        .or().like("tags", keyword));
            }
        }

        // 标签搜索
        if (StringUtils.hasText(tags)) {
            String[] tagArray = tags.split(",");
            queryWrapper.and(wrapper -> {
                for (String tag : tagArray) {
                    if (StringUtils.hasText(tag.trim())) {
                        wrapper.like("tags", tag.trim());
                    }
                }
            });
        }

        // 用户搜索
        if (userId != null) {
            queryWrapper.eq("user_id", userId);
        }

        // 日期范围
        applyDateRange(queryWrapper, startDate, endDate);

        // 数量过滤
        if (minViews != null && minViews > 0) {
            queryWrapper.ge("view_count", minViews);
        }
        if (minAnswers != null && minAnswers > 0) {
            queryWrapper.ge("answer_count", minAnswers);
        }

        applySortOrder(queryWrapper, sort);

        Page<Question> questionPage = questionMapper.selectPage(page, queryWrapper);
        Page<QuestionVO> voPage = convertToQuestionVOPage(questionPage);

        if (StringUtils.hasText(keyword)) {
            asyncRecordSearch(keyword.trim());
        }

        return voPage;
    }

    @Override
    @CacheEvict(value = {"searchQuestions", "searchUsers", "hotKeywords", "searchSuggestions",
        "searchTags", "searchAll"}, allEntries = true)
    public boolean clearSearchCache(Integer type) {
        log.debug("清除搜索缓存: 类型={}", type);

        try {
            switch (type) {
                case 1:
                    // 清除全部缓存
                    Set<String> allKeys = redisTemplate.keys("search:*");
                    if (allKeys != null && !allKeys.isEmpty()) {
                        redisTemplate.delete(allKeys);
                    }
                    return true;
                case 2:
                case 3:
                    redisTemplate.delete(hotKeywordsKey);
                    return true;
                case 4:
                    return true; // 注解已处理
                default:
                    return false;
            }
        } catch (Exception e) {
            log.error("清除缓存失败", e);
            return false;
        }
    }

    @Override
    public Page<QuestionVO> searchQuestions(String keyword, Page<Question> page) {
        return searchQuestions(keyword, page, 1);
    }

    // ==================== 私有辅助方法 ====================
    /**
     * 异步记录搜索关键词
     */
    @Async
    public void asyncRecordSearch(String keyword) {
        try {
            updateHotKeyword(keyword);
        } catch (Exception e) {
            log.error("记录搜索失败: {}", e.getMessage());
        }
    }

    /**
     * 构建搜索查询条件
     */
    private QueryWrapper<Question> buildSearchQueryWrapper(String[] keywords, String originalKeyword) {
        QueryWrapper<Question> queryWrapper = new QueryWrapper<>();

        if (keywords.length > 1) {
            queryWrapper.and(wrapper -> {
                for (String k : keywords) {
                    if (StringUtils.hasText(k)) {
                        wrapper.or(w -> w.like("title", k)
                                .or().like("content", k)
                                .or().like("tags", k));
                    }
                }
            });
        } else {
            queryWrapper.and(wrapper -> wrapper.like("title", originalKeyword)
                    .or().like("content", originalKeyword)
                    .or().like("tags", originalKeyword));
        }

        queryWrapper.eq("status", 1);
        queryWrapper.eq("deleted", 0);

        return queryWrapper;
    }

    /**
     * 应用排序规则
     */
    private void applySortOrder(QueryWrapper<Question> queryWrapper, Integer sort) {
        switch (sort) {
            case 2:
                queryWrapper.orderByDesc("create_time");
                break;
            case 3:
                queryWrapper.orderByDesc("view_count");
                break;
            case 4:
                queryWrapper.orderByDesc("answer_count");
                break;
            case 5:
                queryWrapper.orderByDesc("vote_count");
                break;
            default:
                queryWrapper.orderByDesc("view_count").orderByDesc("create_time");
                break;
        }
    }

    /**
     * 应用日期范围过滤
     */
    private void applyDateRange(QueryWrapper<Question> queryWrapper, String startDate, String endDate) {
        try {
            if (StringUtils.hasText(startDate)) {
                LocalDateTime startDateTime = LocalDate.parse(startDate).atStartOfDay();
                queryWrapper.ge("create_time", startDateTime);
            }
            if (StringUtils.hasText(endDate)) {
                LocalDateTime endDateTime = LocalDate.parse(endDate).plusDays(1).atStartOfDay();
                queryWrapper.lt("create_time", endDateTime);
            }
        } catch (Exception e) {
            log.warn("日期解析失败: {}", e.getMessage());
        }
    }

    /**
     * 从数据库获取热门关键词并缓存
     */
    private List<String> getAndCacheHotKeywordsFromDB(Integer limit) {
        QueryWrapper<SearchKeyword> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("count");
        queryWrapper.last("LIMIT " + limit);

        List<SearchKeyword> keywords = searchKeywordMapper.selectList(queryWrapper);
        List<String> result = keywords.stream()
                .map(SearchKeyword::getKeyword)
                .collect(Collectors.toList());

        // 同步到Redis
        if (!result.isEmpty()) {
            for (SearchKeyword keyword : keywords) {
                redisTemplate.opsForZSet().add(hotKeywordsKey, keyword.getKeyword(), keyword.getCount());
            }
            redisTemplate.expire(hotKeywordsKey, cacheExpiration, TimeUnit.MINUTES);
        }

        return result;
    }

    /**
     * 转换Question分页为QuestionVO分页
     */
    private Page<QuestionVO> convertToQuestionVOPage(Page<Question> questionPage) {
        Page<QuestionVO> voPage = new Page<>(questionPage.getCurrent(), questionPage.getSize(), questionPage.getTotal());
        List<QuestionVO> records = questionPage.getRecords().stream()
                .map(this::convertToQuestionVO)
                .collect(Collectors.toList());
        voPage.setRecords(records);
        return voPage;
    }

    /**
     * 转换User分页为UserVO分页
     */
    private Page<UserVO> convertToUserVOPage(Page<User> userPage) {
        Page<UserVO> voPage = new Page<>(userPage.getCurrent(), userPage.getSize(), userPage.getTotal());
        List<UserVO> records = userPage.getRecords().stream()
                .map(this::convertUserToVO)
                .collect(Collectors.toList());
        voPage.setRecords(records);
        return voPage;
    }

    /**
     * 更新热门关键词统计
     */
    private void updateHotKeyword(String keyword) {
        redisTemplate.opsForZSet().incrementScore(hotKeywordsKey, keyword, 1);
        redisTemplate.expire(hotKeywordsKey, cacheExpiration, TimeUnit.MINUTES);

        CompletableFuture.runAsync(() -> {
            try {
                QueryWrapper<SearchKeyword> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("keyword", keyword);
                SearchKeyword existKeyword = searchKeywordMapper.selectOne(queryWrapper);

                if (existKeyword != null) {
                    existKeyword.setCount(existKeyword.getCount() + 1);
                    searchKeywordMapper.updateById(existKeyword);
                } else {
                    SearchKeyword newKeyword = new SearchKeyword();
                    newKeyword.setKeyword(keyword);
                    newKeyword.setCount(1);
                    searchKeywordMapper.insert(newKeyword);
                }
            } catch (Exception e) {
                log.error("更新关键词统计失败", e);
            }
        });
    }

    /**
     * 获取最新问题
     */
    private Page<QuestionVO> getLatestQuestions(Page<Question> page) {
        QueryWrapper<Question> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", 1);
        queryWrapper.eq("deleted", 0);
        queryWrapper.orderByDesc("create_time");

        Page<Question> questionPage = questionMapper.selectPage(page, queryWrapper);
        return convertToQuestionVOPage(questionPage);
    }

    /**
     * 转换Question为QuestionVO
     */
    private QuestionVO convertToQuestionVO(Question question) {
        QuestionVO vo = new QuestionVO();
        BeanUtils.copyProperties(question, vo);

        // 设置作者信息
        User user = userService.getById(question.getUserId());
        if (user != null) {
            vo.setNickname(user.getNickname());
            vo.setAvatar(user.getAvatar());
            vo.setUsername(user.getUsername());

            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            vo.setUser(userVO);
        }

        // 设置分类信息
        if (question.getCategoryId() != null) {
            try {
                Category category = categoryService.getById(question.getCategoryId());
                if (category != null) {
                    vo.setCategoryName(category.getName());
                }
            } catch (Exception e) {
                vo.setCategoryName("未分类");
            }
        }

        // 格式化标签
        if (StringUtils.hasText(question.getTags())) {
            vo.setTagList(Arrays.asList(question.getTags().split(",")));
        }

        return vo;
    }

    /**
     * 转换User为UserVO
     */
    private UserVO convertUserToVO(User user) {
        UserVO vo = new UserVO();
        BeanUtils.copyProperties(user, vo);
        return vo;
    }
}
